#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "ThreadPool.h"
#include "DoubleLinkList.h"
#include "StdThread.h"
#include "LinkQueue.h"

#define true 1
#define false 0
#define Sleep_time 10

struct Task
{//一个函数指针，指向一个接受 void * 类型参数并返回 void * 类型的函数。这表示结构体中的任务会执行这个函数。
    void *(*function)(void *);
    void *arg;//void 类型的指针，用于存储传递给函数的参数。
};
typedef struct Task task;//使用 task 来代替 struct Task

task *CreateTask(void *(*func)(void *), void *arg)//创建并初始化一个名为 task 的结构体
{
    task *t = (task *)malloc(sizeof(task));
    if ((t == NULL))
    {
        printf("teask malloc error!\n");
        return NULL;
    }
//将传入的函数指针和参数指针分别赋值给刚刚分配的 task 结构体的 function 和 arg 成员
    t->function = func;
    t->arg = arg;
    return t;
}

void FreeTask(task *t)
{
    free(t);
}

struct ThreadPool
{
    DLlist threads;
    LQueue task_queue;

    int min_thrd_num;   // 最小区间
    int max_thrd_num;   // 最大区间
    int max_queue_size; // 最大容量，保护服务器安全
    int busy_thrd_num;  // 正在忙的线程数量
    int exit_thrd_num;  // 需要退出的数量

    pthread_mutex_t pool_mutex;
    pthread_mutex_t busy_thrd_mutex; // 计数器的锁
    pthread_cond_t queue_not_empty;
    pthread_cond_t queue_not_full; // 队列不满的条件

    Thread *admin_thread; // 管理线程

    int shutdown; // 关闭标志位
};

void *thread_worker(void *arg)//描述线程的工作逻辑
{
    ThreadP *p = (ThreadP *)arg;//将传递给线程的参数 arg 转换为 ThreadP 结构体类型的指针
    //以便在后面的代码中使用线程池的属性和变量。
    while (1) // 做完任务继续抢锁
    {
        pthread_mutex_lock(&p->pool_mutex);//获取线程池的互斥锁，保证线程对线程池的访问是互斥的。
        
        while (LQIsEmpty(&p->task_queue) == true && p->shutdown == false) // 关服更新
        {//检查任务队列是否为空，且线程池未关闭
            pthread_cond_wait(&p->queue_not_empty, &p->pool_mutex);
            //等待条件变量 queue_not_empty，进入阻塞状态。
            if (p->exit_thrd_num > 0)//需要退出的数量
            {//这个条件检查是否有线程需要退出
                p->exit_thrd_num--;
                struct Node *TravelPoint = p->threads.head;
                while (TravelPoint != NULL)
                {
                    Thread *t = (Thread *)TravelPoint->data;
                    if(GetThreadId(t) == pthread_self())//比较当前线程的线程ID是否与指定线程 t 的线程ID相等。
                    {
                        RemoveByElement(&p->threads,t);
                        break;
                    }
                    TravelPoint = TravelPoint->next;
                }
                pthread_mutex_unlock(&p->pool_mutex);
                pthread_exit(NULL);//结束当前线程的执行。
            }
        }

        if (p->shutdown == true)
        {
            pthread_mutex_unlock(&p->pool_mutex);//释放线程池的互斥锁，允许其他线程访问线程池。
            pthread_exit(NULL);
        }

        task *tk = (task *)(*LQPop(&p->task_queue));//从任务队列中取出一个任务
        pthread_mutex_unlock(&p->pool_mutex); // 把线程池的锁放掉
//释放了线程池的互斥锁，允许其他线程获取该锁并继续执行。
        pthread_cond_broadcast(&p->queue_not_full);
//发出条件变量信号，表示队列不再是满的。
        pthread_mutex_lock(&p->busy_thrd_mutex); // 上
        //获取了线程池的互斥锁，阻塞其他线程直到当前线程成功获取锁为止
        p->busy_thrd_num++;
        pthread_mutex_unlock(&p->busy_thrd_mutex);
        tk->function(tk->arg); // 调用这个函数，传进这个参数
//调用任务中存储的函数指针，传递任务参数，即执行具体的任务。
        pthread_mutex_lock(&p->busy_thrd_mutex);
        p->busy_thrd_num--;//执行完任务后，相应地更新忙碌线程数量。
        pthread_mutex_unlock(&p->busy_thrd_mutex);

        FreeTask(tk);
    }
}

void *thread_manager(void *arg)//动态地管理线程池中的线程数量
{
    ThreadP *p = (ThreadP *)arg;
    while (p->shutdown != true)//进入一个无限循环，只要线程池没有被关闭。
    {
        sleep(Sleep_time);//用来控制管理线程的执行频率。
        pthread_mutex_lock(&p->pool_mutex);

        // create
        int queueLen = GetQueueLen(&p->task_queue);//获取任务队列长度
        int thread_num = GetListLen(&p->threads);//线程列表中线程的数量
        if (p->busy_thrd_num < queueLen && thread_num < p->max_thrd_num)
        {
            int add = (queueLen / 2) > (p->max_thrd_num - thread_num)
                          ? (p->max_thrd_num - thread_num)
                          : (queueLen / 2);
            for (int i = 0; i < add; i++)
            {
                Thread *t = InitThread(thread_worker, p);
                InsertTail(&p->threads, t);
            }
        }

        // destory
        if (thread_num > p->busy_thrd_num * 2 && thread_num > p->min_thrd_num)
        {
            int minus_thrd_num = (thread_num - p->busy_thrd_num) / 2;
            int minus = minus_thrd_num > (thread_num - p->min_thrd_num) ?
             (thread_num - p->min_thrd_num) : minus_thrd_num;

            p->exit_thrd_num = minus;
            pthread_mutex_unlock(&p->pool_mutex); // 放开
            for (int i = 0; i < minus; i++)
            {
                pthread_cond_broadcast(&p->queue_not_empty);
            }//条件变量操作的函数，它会广播信号，唤醒等待在条件变量上的所有线程。
            continue;
        }
        pthread_mutex_unlock(&p->pool_mutex); // 放开
    }
    pthread_exit(NULL);
}//动态地管理线程池中的线程数量，确保适当数量的线程在执行任务，并根据任务的情况动态地创建或关闭线程，以达到线程池的优化和资源利用的目的。

ThreadP *InitThreadPool(int max_thrd_num, int min_thrd_num, int max_queue_num)
//ThreadP *InitThreadPool(int min_thrd_num, int max_thrd_num, int max_queue_num)
{
    ThreadP *p = (ThreadP *)malloc(sizeof(ThreadP));
    if (p == NULL)
    {
        printf("InitThreadPool malloc error!\n");
        return NULL;
    }

    InitDLlist(&p->threads);
    LQInit(&p->task_queue);//初始化线程列表和任务队列。

    p->max_queue_size = max_queue_num;
    p->min_thrd_num = min_thrd_num;
    p->max_thrd_num = max_thrd_num;
    p->busy_thrd_num = 0;
    p->exit_thrd_num = 0;
//设置线程池结构体中的各种属性
    pthread_mutex_init(&p->pool_mutex, NULL);//线程池锁的初始化
    pthread_mutex_init(&p->busy_thrd_mutex, NULL);
    pthread_cond_init(&p->queue_not_empty, NULL);
    pthread_cond_init(&p->queue_not_full, NULL);

    p->shutdown = false;

    for (int i = 0; i < p->max_thrd_num; i++)
    {
        Thread *t = InitThread(thread_worker, p);
        InsertTail(&p->threads, t);
    }

    p->admin_thread = InitThread(thread_manager, p);

    return p;
}

void ThreadP_AddTask(ThreadP *p, void *(func)(void *), void *arg)//将任务添加到线程池的函数
{
    pthread_mutex_lock(&p->pool_mutex); // 上锁
    while (GetQueueLen(&p->task_queue) == p->max_queue_size)//任务队列是否已满
    {
        pthread_cond_wait(&p->queue_not_full, &p->pool_mutex);
    }//调用 pthread_cond_wait 阻塞当前线程，等待条件变量 queue_not_full 的信号。

    if (p->shutdown == true)
    {
        pthread_mutex_unlock(&p->pool_mutex);
        return;//释放互斥锁并直接返回，不再添加任务。
    }
    LQPush(&p->task_queue, CreateTask(func, arg));//这个任务推入线程池的任务队列
    pthread_cond_broadcast(&p->queue_not_empty);
    //发送条件变量信号，通知等待在 queue_not_empty 上的线程，任务队列中有任务可以执行了。
    pthread_mutex_unlock(&p->pool_mutex);
}

void DestoryThreadPool(ThreadP *p)
{
    if(p == NULL)
    {
        return;
    }

    p->shutdown = true;//将线程池的 shutdown 标志设置为 true，表示线程池正在关闭。

    JoinThread(p->admin_thread);//等待管理线程 admin_thread 结束，并释放其占用的资源。
    free(p->admin_thread);

    int len = GetListLen(&p->threads);
    for (int i = 0; i < len; i++)
    {
        pthread_cond_broadcast(&p->queue_not_empty);
    }//发送条件变量信号给所有等待在 queue_not_empty 上的线程，以唤醒它们

    struct Node *travelPoint = p->threads.head;
    while (travelPoint != NULL)
    {
        Thread *t = (Thread *)travelPoint->data;
        JoinThread(t);
        free(t);
        travelPoint = travelPoint->next;
    }
    FreeDLlist(&p->threads);
    //遍历线程池中的线程列表，等待每个线程结束，并释放它们的内存。
    while(LQIsEmpty(&p->task_queue) != true)
    {
        task *t = (task*)(*LQPop(&p->task_queue));
        free(t);//从任务队列中弹出一个任务，并将其转换为 task 结构体类型的指针 t。
    }
    FreeQueue(&p->task_queue);

    pthread_mutex_destroy(&p->pool_mutex);
    pthread_mutex_destroy(&p->busy_thrd_mutex);
//销毁线程池的互斥锁和忙碌线程互斥锁。
    pthread_cond_destroy(&p->queue_not_empty);
    pthread_cond_destroy(&p->queue_not_full);
}//销毁线程池的条件变量 queue_not_empty 和 queue_not_full。
